
#region Imported Namespaces
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Web;
using System.Web.UI;
using System.Web.UI.Design;
using System.Web.UI.WebControls;
#endregion

namespace PHSRAG.WebControls
{
	#region Class Annunciator
	/// <summary>
	/// The Annunciator allows the display of a message along with a title. Typical use of this control is to embed an
	/// instance of it either at the top or the bottom of a page (or whereever it suits your fancy).
	/// The Annunciator will only display itself when its message property is set to a string of non-zero length.
	/// </summary>
	/// <remarks>
	/// <p>Any page which would like to display a message (optionally with a title) should include this control on the page.
	/// Both the Title and the Message may be set either at design time (in HTML) or at runtime (through the instance).</p>
	/// <p>Typically, the container of this control is a HTML table. We would like that container and the Annunciator
	/// not to occupy any client real-estate until such time that the Annunciator has something to display. This is
	/// controlled by setting the style on both the container and the table created during control-tree generation to render
	/// them invisible. When it is time to show something, both the container and the table are rendered visible.
	/// Client-side scrpting is used to do this.</p>
	/// <p>To enable the Annunciator to control the visibility of its conatiner, the <b>ContainerID</b> property
	/// should be set to the ID of its container (as shown in the example below).</p>
	/// </remarks>
	/// <example>
	/// The following example shows how the page would use this control. The registration of the control can be done
	/// simply by dropping the control on the page in design mode.
	/// <code>
	/// <![CDATA[
	/// <%@ Register TagPrefix="cc1" Namespace="PHSRAG.WebControls" Assembly="PHSRAG.WebControls" %>
	/// ...
	/// <body>
	/// ...
	/// <table id="dynamicTable" style="visibility:hidden;display:none">
	///		<tr><td><cc1:annunciator id="annunciator" title="Hi" runat="server" Message="Hello" ContainerID="dynamicTable"/></td></tr>
	///	</table>
	/// ...
	/// </body>
	/// ]]>
	/// </code>
	/// </example>
	[ToolboxData("<{0}:Annunciator runat=server />"), Designer(typeof(AnnunciatorDesigner))]
	public class Annunciator : System.Web.UI.WebControls.WebControl, INamingContainer
	{

		public enum MessageTypes
		{
			Informational,
			Warning,
			Error
		}

		#region Constants
		private const string TableID = "annunciatorTable";
		#endregion

		#region Instance Variables
		private string containerID;
		private Label title;
		private Label message;
		private MessageTypes messageType = MessageTypes.Informational;
		#endregion

		#region Properties
		/// <summary>
		/// Get/Set the ID of the conatainer.
		/// </summary>
		public string ContainerID
		{
			set { containerID = value; }
		}

		/// <summary>
		/// Get/Set the annunciator message. When set to an empty string, the entire Annunciator hides itself.
		/// </summary>
		[Bindable(true), Category("Appearance"), DefaultValue("")]
		public string Message
		{
			get { EnsureChildControls(); return message.Text; }
			set { EnsureChildControls(); message.Text = value; ShowMessage(); }
		}

		/// <summary>
		/// Get/Set the annunciator title.
		/// NB: Setting the title is currently NOT allowed (it will be ignored and set to "")
		/// until there is a method to differentiate information, warnings, and error messages
		/// (deemed too high risk for initial 2.1 release)
		/// </summary>
		[Bindable(true), Category("Appearance"), DefaultValue("")]
		public string Title
		{
			get { EnsureChildControls(); return title.Text; }
			set { EnsureChildControls(); title.Text = ""; }
		}

		/// <summary>
		/// Get/Set whether or not the message being displayed is an error.
		/// </summary>
		[Bindable(true), Category("Appearance"), DefaultValue("")]
		public MessageTypes MessageType
		{
			set { EnsureChildControls(); messageType = value; }
		}
		#endregion

		#region Private Properties
		private static bool IsDesignMode
		{
			get { return HttpContext.Current == null; }
		}
		#endregion

		#region Overrides
		/// <summary>
		/// Create all controls that will be on the Annunciator. Notice that the creation is more than just instantiating
		/// the controls. It also involves in generating the underlying HTML so that the controls shows up per the need.
		/// </summary>
		protected override void CreateChildControls()
		{
			CreateControls();
			GenerateControlTree();
		}

		/// <summary>
		/// Ensure that child control are created and show the message (if any).
		/// </summary>
		/// <param name="e">Argument associated with the event</param>
		protected override void OnLoad(EventArgs e)
		{
			base.OnLoad(e);
			EnsureChildControls();
			ShowMessage();
		}
		#endregion

		#region Private Methods
		/// <summary>
		/// Create all controls in the Header.
		/// </summary>
		/// <remarks>
		/// The control initializes both the title and message control to be invisible. Their visibility is ultimately
		/// controlled through the Message property. The controls are made visible only when the Message is set to
		/// a non-zero length string.
		/// </remarks>
		private void CreateControls()
		{
			Controls.Clear();
			title = new Label();
			message = new Label();
			title.Visible = message.Visible = false;
		}

		/// <summary>
		/// Setup the control tree to reflect the actual (and exact) layout of the controls within the Header.
		/// </summary>
		private void GenerateControlTree()
		{
			Controls.Add(new LiteralControl(string.Format(
				"<table id=\"{0}\" style=\"visibility:hidden;display:none;\" class=\"Annunciator\">\n" +
				"\t<tr class=\"Title\">\n" +
				"\t\t<td>", TableID)));
			Controls.Add(title);

			Controls.Add(new LiteralControl(string.Format("</td></tr><tr class=\"{0}\"><td>", messageType.ToString("F"))));
			Controls.Add(message);
			Controls.Add(new LiteralControl("</td></tr></table>"));
		}

		/// <summary>
		/// Register the client-side javascript functions to show the title/message.
		/// </summary>
		/// <remarks>
		/// <p>Typically we would like this control not to occupy any client real-estate until such time that the control
		/// has something to display. This is controlled by setting the style on both the container (in HTML) and the table
		/// created during control-tree generation to render them invisible. When it is time to show something, both the
		/// container and the table are rendered visible. Client-side scrpting is used to do this.</p>
		/// </remarks>
		private void RegisterScripts()
		{
			const string scriptBlockKey = "AnnunciatorScript";
			if (!Page.ClientScript.IsStartupScriptRegistered(scriptBlockKey))
				Page.ClientScript.RegisterStartupScript(GetType(), scriptBlockKey, string.Format(
					"<script language='javascript'>\n" +
					"function ShowAnnunciator()\n" +
					"{{\n" +
					"\tvar t = document.getElementById('{0}');\n" +
					"\tif (t != null) {{ t.style.visibility = 'visible'; t.style.display = 'block'; }}\n" +
					"\tt = document.getElementById('{1}');\n" +
					"\tif (t != null) {{ t.style.visibility = 'visible'; t.style.display = 'block'; }}\n" +
					"}}\n\n" +
					"ShowAnnunciator();\n" +
					"</script>\n", containerID, TableID));
		}

		/// <summary>
		/// If we have any message to show, render the title/message controls visible, and register the client-side
		/// scripts to make the Annunciator visible.
		/// </summary>
		private void ShowMessage()
		{
			title.Visible = message.Visible = (message.Text.Length > 0);
			if (!IsDesignMode && message.Visible)
				RegisterScripts();
		}
		#endregion
	}
	#endregion

	#region Class AnnunciatorDesigner
	/// <summary>
	/// Designer associated with the Annunciator control.
	/// </summary>
	/// <remarks>
	/// This class cannot be used directly.
	/// </remarks>
	public class AnnunciatorDesigner : ControlDesigner
	{
		#region Overrides
		/// <summary>
		/// Since the Annunciator control does not have any design-time visibility, the designer provides
		/// the type name of that control and the name of the instance.
		/// </summary>
		/// <returns>HTML representation of the Annunciator control</returns>
		public override string GetDesignTimeHtml()
		{
			return CreatePlaceHolderDesignTimeHtml();
		}
		#endregion
	}
	#endregion
}

// --- EOF ---
